package com.yfunc.common.persistence.ibatis;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Transient;

import org.apache.ibatis.jdbc.SQL;

import com.yfunc.common.util.Strings;

public class EntityInfo {

	private String tableName;
	private List<String> fields;
	private String id;
	private boolean autoGeneratedId;

	public EntityInfo(Class<?> entityClazz) {
		this.fields = new ArrayList<String>();
		setEntityInfo(entityClazz);
	}

	private void setEntityInfo(Class<?> entityClazz) {
		if (!entityClazz.isAnnotationPresent(Entity.class)) {
			throw new RuntimeException("Not Implements @Entity Annotation!");
		}
		
		String entityName = getAnnocationValue(entityClazz.getAnnotation(Entity.class));
		this.tableName =  entityName ==null ? entityClazz.getSimpleName() : entityName;

		for (Field field : entityClazz.getDeclaredFields()) {
			if (field.isAnnotationPresent(Id.class)) {
				String value = getAnnocationValue(field.getAnnotation(Column.class));
				this.id = value != null ?  value : field.getName();
				this.autoGeneratedId = field.isAnnotationPresent(GeneratedValue.class);
			} else if (field.isAnnotationPresent(Transient.class)) {
				continue;
			}else if (field.isAnnotationPresent(Column.class)) {
				String value = getAnnocationValue(field.getAnnotation(Column.class));
				this.fields.add(value != null ?  value : field.getName());
			} else {
				this.fields.add(field.getName());
			}
		}
	}

	private String getAnnocationValue(Annotation annotation) {
		
		if(annotation == null) {
			return null;
		}
		
		if (annotation instanceof Entity) {
			Entity entityAnnotation = (Entity) annotation;

			return entityAnnotation.name() != null
					&& !entityAnnotation.name().equals("") ? entityAnnotation
					.name() : null;
					
		} else if( annotation instanceof Column) {
			Column columnAnnotation = (Column) annotation;
			return columnAnnotation.name() != null
					&& !columnAnnotation.name().equals("") ? columnAnnotation
					.name() : null;
		}
		return null;
	}

	private String getExpression(String column) {
		return Strings.value("#{{0}}", column);
	}
	
	

	public String tableName() {
		return tableName;
	}

	public List<String> fields() {
		return fields;
	}

	public String id() {
		return id;
	}

	public String insertSQL() {
		SQL sql = new SQL();
		sql.INSERT_INTO(this.tableName);
		if (!autoGeneratedId) {
			sql.VALUES(this.id, getExpression(this.id));
		}
		for (String column : this.fields) {
			sql.VALUES(column, getExpression(column));
		}
		return sql.toString();
	}

	public String updateSQL() {
		SQL sql = new SQL();
		sql.UPDATE(this.tableName);
		for (String column : this.fields) {
			sql.SET(column + "=" + getExpression(column));
		}
		sql.WHERE(this.id + "=" + getExpression(id));
		return sql.toString();
	}

	public String deleteSQL() {
		return new SQL().DELETE_FROM(tableName)
				.WHERE(this.id + "=" + getExpression(id)).toString();
	}

	public String fingByIdSQL() {
		SQL sql = new SQL();

		sql.SELECT(this.id);
		for (String column : this.fields) {
			sql.SELECT(column);
		}
		return sql.FROM(tableName).WHERE(this.id + "=" + getExpression(id))
				.toString();
	}

	public String fingAllSQL() {
		SQL sql = new SQL();

		sql.SELECT(this.id);
		for (String column : this.fields) {
			sql.SELECT(column);
		}
		return sql.FROM(tableName).toString();
	}

}
